/**
 * 读取配置文件
 */
'use strict';

import * as nconf from 'nconf';
import * as path from 'path';
import { existsSync, mkdirSync } from 'fs';
import { networkInterfaces, userInfo } from 'os';

/** 文件配置 */
interface IFileConfig {
    /** 文件模板路径 */
    template: string;
    /** 文件导出路径 */
    export: string;
    /** 文件上传路径 */
    upload: string;
    /** 图片路径 */
    images: string;
    /**静态文件路径 */
    staticfile: string
}

/**微信配置模型 */
interface IWechatConfig {
    grant_type: string,
    appid: string;
    appsecret: string;
    noncestr: string;
    access_tokenUrl: string;
    accessTokenUrl: string;
    ticketUrl: string;
    getimageUrl: string;
    cache_duration: number,
    paytotal: string,
    wx_mch_id: string,
    wx_mch_key: string,
    notify_url: string
}

/**短信接口配置 */
interface smsConfig {
    url: string,
    AccessKeyID: string,
    AccessKeySecret: string,
    originname: string,
    TemplateCode: string
}
interface ISession {
    appsecret: string;
    key: string;
    expire: number;
    prefix: string;
}

/** 模式*/
enum schema {
    development = 1,
    production
};

module schema {
    export function parse(envstr: string) {
        return this[envstr.trim().toLocaleLowerCase()] as number;
    };
    export function convert(envval: number): schema {
        return this[envval];
    };
}








class ConfigProvider extends nconf.Provider {

    /**是否是开发模式 */
    isDevelopment: Boolean;
    /**文件路径 */
    filePath: IFileConfig;

    /**微信配置 */
    wechat: IWechatConfig;

    /** 短信接口URL */
    sms: smsConfig;

    /**是否启用Token校验 */
    enabledToken: Boolean;
    /**是否启用URL校验 */
    enabledUrl: Boolean;

    /**
     * 路由代理
     */
    proxys: Array<{
        method: 'get',
        routepath: string,
        // pattern: string,
        file?: { path: string },
    }>;
    session: {
        secrets: string,
        key: string,
        expire: number,
        prefix: string
    };
    getValue: (key: any, env?: schema) => any;
}


class Config {
    config: ConfigProvider;
    private root: string;
    // private NODE_ENV: schema;

    constructor() {
        const env = this.envInit();
        const config = this.configInit(env);

        config.filePath = this.getFilePath(config.getValue("file"))
        config.wechat = config.getValue('wechat');
        config.sms = config.getValue('sms');
        config.enabledToken = config.get('enabledToken');
        config.enabledUrl = config.get('enabledUrl');
        this.config = config;
    }
    private configInit(env: schema) {
        let config: ConfigProvider = nconf.argv().env().file({ file: `${path.join(__dirname, '../..')}/config.json` }) as ConfigProvider;

        config.set("env", schema.convert(env));
        this.root = path.join(__dirname, '..');
        config.set("root", this.root);
        config.isDevelopment = env === schema.development;
        config.getValue = function (key: string, _env?: schema) {
            const envstr = schema.convert(_env);
            const data = envstr ? this.get(key)[envstr] : this.get(key);
            if (data === undefined) {
                const msg = `配置文件中未配置(${key}${envstr ? ':' : ''}${envstr ? envstr : ''})`;
                throw Error(msg);
            } else {
                return data
            };
        };
        return config;
    };
    /**
     * 验证启动模式
     */
    private envInit() {
        let env: number;
        if (process.env && process.env.NODE_ENV) {
            env = schema.parse(process.env.NODE_ENV);
            if (env === undefined) {
                throw new Error(`NODE_ENV 设置错误 必需为${schema.development} 或者 ${schema.production}`);
            }
            console.log(`当前为：${env === schema.development ? '开发模式' : '生产模式'}`);
        } else {
            env = schema.development;
            console.log("未设置NODE_ENV,默认为开发模式", `部署后强制设置为:生产模式(${schema.production})`)
        }
        return env;
    }
    private getSession(obj: any, isdev: Boolean): any {
        let storage_spaces: Array<string> = obj.storage_spaces;
        if (storage_spaces && Array.isArray(storage_spaces) && storage_spaces.length > 0) {
        } else {
            storage_spaces = ['kalends'];
        }
        if (isdev) {
            const _tarr = [];
            _tarr.push(process.env.COMPUTERNAME);
            _tarr.push(process.env.OS);
            _tarr.push(process.env.USERNAME);
            const netif = networkInterfaces();
            for (const key in netif) {
                console.log(key);
                if (netif.hasOwnProperty(key)) {
                    const element: Array<{
                        family: string,
                        address: string
                    }> = netif[key];
                    if (element && Array.isArray(element)) {
                        const ips = element.filter(itm => itm
                            && itm.family && itm.family === 'IPv4'
                            && itm.address && itm.address.substring(0, 4) !== '127.');
                        if (ips.length > 0) {
                            _tarr.push(ips[0].address);
                            break;
                        }
                    }
                }
            }
            storage_spaces.push(_tarr.join('-'));
        }
        obj.prefix = `${storage_spaces.join(":")}:session:`
        return obj;
    }

    /**
     * 判断文件夹是否存在，不存在则创建
     */
    private dirThereIsNoCreation = (pathstr: string) => {
        if (!existsSync(pathstr)) {
            const dirparse = path.parse(pathstr);
            this.dirThereIsNoCreation(dirparse.dir)
            mkdirSync(pathstr);
        }
    };
    private getFilePath(obj: any) {
        const _rp = path.join(this.root, '..');
        const getfilepath = (root: string, ostr: string) => {
            return path.join(root, ostr.replace("$root$", ""));
        };
        let templatestr: string = getfilepath(_rp, obj.template);
        let uploadstr: string = getfilepath(_rp, obj.upload);
        let exportstr: string = getfilepath(_rp, obj.export);
        let imagesstr: string = getfilepath(_rp, obj.images);
        let staticfilestr: string = getfilepath(_rp, obj.staticfile);
        this.dirThereIsNoCreation(exportstr);
        return {
            template: templatestr,
            export: exportstr,
            upload: uploadstr,
            images: imagesstr,
            staticfile: staticfilestr
        } as IFileConfig;
    }
}

export default new Config().config;